import React, {
  ForwardedRef,
  useEffect,
  useImperativeHandle,
  useLayoutEffect,
  useRef
} from 'react';
import * as echarts from 'echarts/core';
import { EChartsType } from 'echarts/core';
import {
  DatasetComponent,
  DatasetComponentOption,
  DataZoomComponent,
  DataZoomComponentOption,
  GridComponent,
  GridComponentOption,
  LegendComponent,
  LegendComponentOption,
  TitleComponent,
  TitleComponentOption,
  ToolboxComponent,
  ToolboxComponentOption,
  TooltipComponent,
  TooltipComponentOption,
  GraphicComponent
} from 'echarts/components';
import {
  BarChart,
  BarSeriesOption,
  LineChart,
  LineSeriesOption,
  PieChart,
  PieSeriesOption
} from 'echarts/charts';
import { UniversalTransition } from 'echarts/features';
import { SVGRenderer } from 'echarts/renderers';
import { ECElementEvent } from 'echarts/types/src/util/types';
import { Spin } from 'antd';

echarts.use([
  DatasetComponent,
  DataZoomComponent,
  GridComponent,
  LegendComponent,
  TitleComponent,
  ToolboxComponent,
  TooltipComponent,
  BarChart,
  LineChart,
  PieChart,
  UniversalTransition,
  SVGRenderer,
  GraphicComponent
]);

export type ChartOption = echarts.ComposeOption<DatasetComponentOption
  | DataZoomComponentOption
  | GridComponentOption
  | LegendComponentOption
  | TitleComponentOption
  | ToolboxComponentOption
  | TooltipComponentOption
  | BarSeriesOption
  | LineSeriesOption
  | PieSeriesOption
>;

export interface ChartProps {
  option: ChartOption | null | undefined;
  width: number | string;
  height: number | string;
  loading?: boolean;
  onClick?(event: ECElementEvent): any;
};

export interface ChartRef {
  instance(): EChartsType | undefined;
};

const ChartInner: React.ForwardRefRenderFunction<ChartRef, ChartProps> = (
  {
    option,
    width,
    height,
    loading = false,
    onClick
  },
  ref: ForwardedRef<ChartRef>
) => {
  const cRef = useRef<HTMLDivElement>(null);
  const cInstance = useRef<EChartsType>();

  useEffect(() => {
    if (cRef.current) {
      cInstance.current = echarts.getInstanceByDom(cRef.current);
      if (!cInstance.current) {
        cInstance.current = echarts.init(cRef.current, null, { renderer: 'svg', locale: 'ZH' });
        cInstance.current.on('click', event => {
          const ec = event as ECElementEvent;
          if (ec && onClick) {
            onClick(ec);
          }
        });
      }
      if (option) {
        cInstance.current?.setOption(option);
      }
    }
  }, [cRef, option, onClick]);

  useEffect(() => {
    window.addEventListener('resize', resize);
    return () => {
      window.removeEventListener('resize', resize);
    };
  }, [option]);

  useLayoutEffect(() => {
    resize();
  }, [width, height]);

  const resize = () => {
    cInstance.current?.resize({
      animation: { duration: 300 }
    });
  };

  const instance = () => {
    return cInstance.current;
  };

  useImperativeHandle(ref, () => ({
    instance
  }));

  return (
    <Spin spinning={loading}>
      <div
        ref={cRef}
        style={{width: width, height: height}}
      />
    </Spin>
  );
};

const Chart = React.forwardRef(ChartInner);

export default Chart;
